# LocalStack Resource Provider Scaffolding v2
from __future__ import annotations

from copy import deepcopy
from pathlib import Path
from typing import Optional, TypedDict

import localstack.services.cloudformation.provider_utils as util
from localstack.services.cloudformation.resource_provider import (
    OperationStatus,
    ProgressEvent,
    ResourceProvider,
    ResourceRequest,
)


class ApiGatewayMethodProperties(TypedDict):
    HttpMethod: Optional[str]
    ResourceId: Optional[str]
    RestApiId: Optional[str]
    ApiKeyRequired: Optional[bool]
    AuthorizationScopes: Optional[list[str]]
    AuthorizationType: Optional[str]
    AuthorizerId: Optional[str]
    Integration: Optional[Integration]
    MethodResponses: Optional[list[MethodResponse]]
    OperationName: Optional[str]
    RequestModels: Optional[dict]
    RequestParameters: Optional[dict]
    RequestValidatorId: Optional[str]


class IntegrationResponse(TypedDict):
    StatusCode: Optional[str]
    ContentHandling: Optional[str]
    ResponseParameters: Optional[dict]
    ResponseTemplates: Optional[dict]
    SelectionPattern: Optional[str]


class Integration(TypedDict):
    Type: Optional[str]
    CacheKeyParameters: Optional[list[str]]
    CacheNamespace: Optional[str]
    ConnectionId: Optional[str]
    ConnectionType: Optional[str]
    ContentHandling: Optional[str]
    Credentials: Optional[str]
    IntegrationHttpMethod: Optional[str]
    IntegrationResponses: Optional[list[IntegrationResponse]]
    PassthroughBehavior: Optional[str]
    RequestParameters: Optional[dict]
    RequestTemplates: Optional[dict]
    TimeoutInMillis: Optional[int]
    Uri: Optional[str]


class MethodResponse(TypedDict):
    StatusCode: Optional[str]
    ResponseModels: Optional[dict]
    ResponseParameters: Optional[dict]


REPEATED_INVOCATION = "repeated_invocation"


class ApiGatewayMethodProvider(ResourceProvider[ApiGatewayMethodProperties]):
    TYPE = "AWS::ApiGateway::Method"  # Autogenerated. Don't change
    SCHEMA = util.get_schema_path(Path(__file__))  # Autogenerated. Don't change

    def create(
        self,
        request: ResourceRequest[ApiGatewayMethodProperties],
    ) -> ProgressEvent[ApiGatewayMethodProperties]:
        """
        Create a new resource.

        Primary identifier fields:
          - /properties/RestApiId
          - /properties/ResourceId
          - /properties/HttpMethod

        Required properties:
          - RestApiId
          - ResourceId
          - HttpMethod

        Create-only properties:
          - /properties/RestApiId
          - /properties/ResourceId
          - /properties/HttpMethod



        IAM permissions required:
          - apigateway:PUT
          - apigateway:GET

        """
        model = request.desired_state
        apigw = request.aws_client_factory.apigateway
        operation_model = apigw.meta.service_model.operation_model

        apigw.put_method(
            **util.convert_request_kwargs(model, operation_model("PutMethod").input_shape)
        )

        # setting up integrations
        integration = model.get("Integration")
        if integration:
            apigw.put_integration(
                restApiId=model.get("RestApiId"),
                resourceId=model.get("ResourceId"),
                httpMethod=model.get("HttpMethod"),
                **util.convert_request_kwargs(
                    integration, operation_model("PutIntegration").input_shape
                ),
            )

            integration_responses = integration.pop("IntegrationResponses", [])
            for integration_response in integration_responses:
                apigw.put_integration_response(
                    restApiId=model.get("RestApiId"),
                    resourceId=model.get("ResourceId"),
                    httpMethod=model.get("HttpMethod"),
                    **util.convert_request_kwargs(
                        integration_response, operation_model("PutIntegrationResponse").input_shape
                    ),
                )

        responses = model.get("MethodResponses", [])
        for response in responses:
            apigw.put_method_response(
                restApiId=model.get("RestApiId"),
                resourceId=model.get("ResourceId"),
                httpMethod=model.get("HttpMethod"),
                **util.convert_request_kwargs(
                    response, operation_model("PutMethodResponse").input_shape
                ),
            )

        return ProgressEvent(
            status=OperationStatus.SUCCESS,
            resource_model=model,
            custom_context=request.custom_context,
        )

    def read(
        self,
        request: ResourceRequest[ApiGatewayMethodProperties],
    ) -> ProgressEvent[ApiGatewayMethodProperties]:
        """
        Fetch resource information

        IAM permissions required:
          - apigateway:GET
        """
        raise NotImplementedError

    def delete(
        self,
        request: ResourceRequest[ApiGatewayMethodProperties],
    ) -> ProgressEvent[ApiGatewayMethodProperties]:
        """
        Delete a resource

        IAM permissions required:
          - apigateway:DELETE
        """

        # FIXME we sometimes get warnings when calling this method, probably because
        #  restAPI or resource has been already deleted
        model = request.desired_state
        apigw = request.aws_client_factory.apigateway

        try:
            apigw.delete_method(
                **util.convert_request_kwargs(
                    model, apigw.meta.service_model.operation_model("DeleteMethod").input_shape
                )
            )
        except apigw.exceptions.NotFoundException:
            pass

        return ProgressEvent(
            status=OperationStatus.SUCCESS,
            resource_model=model,
            custom_context=request.custom_context,
        )

    def update(
        self,
        request: ResourceRequest[ApiGatewayMethodProperties],
    ) -> ProgressEvent[ApiGatewayMethodProperties]:
        """
        Update a resource

        IAM permissions required:
          - apigateway:GET
          - apigateway:DELETE
          - apigateway:PUT
        """
        model = request.desired_state
        apigw = request.aws_client_factory.apigateway
        operation_model = apigw.meta.service_model.operation_model

        must_params = util.select_attributes(
            model,
            [
                "RestApiId",
                "ResourceId",
                "HttpMethod",
            ],
        )

        if integration := deepcopy(model.get("Integration")):
            integration.update(must_params)
            apigw.put_integration(
                **util.convert_request_kwargs(
                    integration, operation_model("PutIntegration").input_shape
                )
            )

        else:
            must_params.update({"AuthorizationType": model.get("AuthorizationType")})
            apigw.put_method(
                **util.convert_request_kwargs(must_params, operation_model("PutMethod").input_shape)
            )

        return ProgressEvent(
            status=OperationStatus.SUCCESS,
            resource_model=model,
            custom_context=request.custom_context,
        )
